package level.editor.main;

import java.awt.Adjustable;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashMap;

import javax.swing.BorderFactory;
import javax.swing.JPanel;
import javax.swing.JScrollBar;
import javax.swing.Scrollable;

import core.Constants;

import level.editor.command.Command;
import level.editor.command.RequiresOutput;
import level.editor.tool.Tool;
import level.state.State;
import level.state.StatePainter;

/*
 * LevelOutput is the main interface. It passes mouse, action, and key events to
 * the LevelView, and then to other Modules. Painting happens here.
 */

public class LevelOutput extends JPanel implements Scrollable,
		AdjustmentListener, MouseListener
{
	private HashMap<String, Image> images;
	private LevelView view;
	private int maxX;
	private int maxY;
	private State state;
	private Tool selectedTool;

	public LevelOutput(LevelView view)
	{
		super(new FlowLayout(FlowLayout.LEADING));
		this.view = view;
		state = null;
		setPreferredSize(new Dimension(
				(int) (Constants.DEFAULT_COLS * Constants.TILE_SIZE),
				(int) (Constants.DEFAULT_ROWS * Constants.TILE_SIZE)));
		setBackground(Color.WHITE);
		images = new HashMap<String, Image>(Constants.CAPACITY,
				Constants.LOADFACTOR);
	}
	
	public void setSelectedTool(Tool tool)
	{
		this.selectedTool = tool;
	}
	
	public Tool getSelectedTool()
	{
		return selectedTool;
	}

	public void setDimension(Dimension d)
	{
		this.maxX = d.width;
		this.maxY = d.height;
	}

	public void setViewBorder(String border)
	{
		view.setBorder(BorderFactory.createTitledBorder(border));
	}

	public HashMap<String, Image> getImages()
	{
		return images;
	}

	public void setState(State state)
	{
		this.state = state;
	}

	public void repaint()
	{
		super.repaint();
		Runtime.getRuntime().gc();
	}

	public void pushUpCommand(Command command)
	{
		view.pushUpCommand(command);
	}

	public void pushDownCommand(Command command)
	{
		if (command instanceof RequiresOutput)
			((RequiresOutput) command).execute(this);
	}

	@Override
	public void paintComponent(Graphics gOld)
	{
		super.paintComponent(gOld);
		Graphics2D g = (Graphics2D) gOld;
		g.setRenderingHints(new RenderingHints(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON));

		StatePainter.paintGrid(g, getPreferredSize().width,
				getPreferredSize().height);

		if (state != null)
		{
			RequestVisibilityCommand command = new RequestVisibilityCommand();
			pushUpCommand(command);

			StatePainter.paintState(state, g, images, command.getVisibility());
		}
	}

	@Override
	public Dimension getPreferredScrollableViewportSize()
	{
		return this.getPreferredSize();
	}

	@Override
	public int getScrollableBlockIncrement(Rectangle arg0, int arg1, int arg2)
	{
		// TODO Auto-generated method stub
		return (int) Constants.TILE_SIZE;
	}

	@Override
	public boolean getScrollableTracksViewportHeight()
	{
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public boolean getScrollableTracksViewportWidth()
	{
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int getScrollableUnitIncrement(Rectangle arg0, int arg1, int arg2)
	{
		return (int) Constants.TILE_SIZE;
	}

	@Override
	public void adjustmentValueChanged(AdjustmentEvent e)
	{
		// Possibly bugged
		JScrollBar source = (JScrollBar) e.getAdjustable();
		int orientation = source.getOrientation();
		int defaultMax = (int) (orientation == Adjustable.HORIZONTAL ? Constants.DEFAULT_COLS
				* Constants.TILE_SIZE
				: Constants.DEFAULT_ROWS * Constants.TILE_SIZE);
		int edgeMax = (int) (source.getVisibleAmount() + source.getValue() + Constants.TILE_SIZE);
		int tileMax = (int) ((orientation == Adjustable.HORIZONTAL ? maxX
				: maxY) + 3 * Constants.TILE_SIZE);

		int max = (defaultMax >= edgeMax ? defaultMax : edgeMax);
		max = (max >= tileMax ? max : tileMax);

		this.setPreferredSize((orientation == Adjustable.HORIZONTAL ? new Dimension(
				max, this.getPreferredSize().height) : new Dimension(this
				.getPreferredSize().width, max)));
	}

	
	@Override
	public void mouseClicked(MouseEvent e)
	{
		
	}
	

	@Override
	public void mouseEntered(MouseEvent e)
	{
		// TODO Auto-generated method stub
		
	}
	

	@Override
	public void mouseExited(MouseEvent e)
	{
		// TODO Auto-generated method stub
		
	}
	

	@Override
	public void mousePressed(MouseEvent e)
	{
		if (selectedTool != null)
			selectedTool.handlePress(e);
	}
	

	@Override
	public void mouseReleased(MouseEvent e)
	{
		
	}

}
